/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package marketrmi;

import bankrmi.Account;
import bankrmi.Bank;
import id2212.homework2.ClientInter;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author yann
 */
public class Item extends UnicastRemoteObject implements marketrmi.ItemInter {

    private int id;
    private String sellerName;
    private String sellerBankPassword;
    private String itemName;
    private int price;
    private int amount;
    private List<Wish> wishList;
    private static final String DATASOURCE = "marketbdd";
    private Statement sqlStatement;
    private AccountClientInter refSeller;

    private synchronized Connection getConnection() throws ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver");
        System.out.println("DRIVER OK ! ");
        Connection connec = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/" + DATASOURCE, "root", "");
        System.out.println("Connection success !");
        return connec;
    }

    public Item(int id, String name, int price, int amount, String nameSeller, String passwordBankSeller) throws RemoteException {
        // connection to the database
        try {
            Connection connection;
            connection = getConnection();
            sqlStatement = connection.createStatement();
        } catch (ClassNotFoundException ex) {
        } catch (SQLException ex) {
        }

        this.itemName = name;
        this.price = price;
        this.amount = amount;
        this.wishList = new ArrayList<Wish>();
        this.sellerName = nameSeller;
        this.sellerBankPassword = passwordBankSeller;

        if (id == 0) {
            ResultSet result = null;
            try {
                sqlStatement.executeUpdate("INSERT INTO item VALUES(0,'" + name + "','" + price + "','" + amount + "','" + sellerName + "')");

                result = sqlStatement.executeQuery("SELECT id FROM item ORDER BY id desc LIMIT 1");
                result.next();
                this.id = result.getInt("id");
                result.close();
                //stock the bankpassword
                sqlStatement.executeUpdate("UPDATE client SET passwordBank='" + passwordBankSeller + "' WHERE name='" + sellerName + "'");
            } catch (SQLException ex) {
                Logger.getLogger(AccountClient.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            this.id = id;
        }
        this.completeWishList();
    }

    public Item(int id, String name, int price, int amount, String nameSeller, String passwordBankSeller, AccountClientInter accSeller) throws RemoteException {
        // connection to the database
        try {
            Connection connection;
            connection = getConnection();
            sqlStatement = connection.createStatement();
        } catch (ClassNotFoundException ex) {
        } catch (SQLException ex) {
        }
        this.refSeller = accSeller;
        this.itemName = name;
        this.price = price;
        this.amount = amount;
        this.wishList = new ArrayList<Wish>();
        this.sellerName = nameSeller;
        this.sellerBankPassword = passwordBankSeller;

        if (id == 0) {
            ResultSet result = null;
            try {
                sqlStatement.executeUpdate("INSERT INTO item VALUES(0,'" + name + "','" + price + "','" + amount + "','" + sellerName + "')");

                result = sqlStatement.executeQuery("SELECT id FROM item ORDER BY id desc LIMIT 1");
                result.next();
                this.id = result.getInt("id");
                result.close();
                sqlStatement.executeUpdate("UPDATE client SET passwordBank='" + passwordBankSeller + "' WHERE name='" + sellerName + "'");
            } catch (SQLException ex) {
                Logger.getLogger(AccountClient.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            this.id = id;
        }
        this.completeWishList();
    }

    @Override
    public synchronized int getId() {
        return id;
    }

    @Override
    public synchronized String getItemName() {
        return itemName;
    }

    @Override
    public synchronized String getSellerName() {
        return sellerName;
    }

    @Override
    public synchronized int getPrice() {
        return price;
    }

    @Override
    public synchronized void setName(String Name) {
        this.itemName = Name;

        try {
            sqlStatement.executeUpdate("UPDATE item SET name='" + Name + "' WHERE id='" + id + "'");
        } catch (SQLException ex) {
            Logger.getLogger(AccountClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public synchronized void setPrice(int price) {
        this.price = price;

        try {
            sqlStatement.executeUpdate("UPDATE item SET price='" + price + "' WHERE id='" + id + "'");
        } catch (SQLException ex) {
            Logger.getLogger(AccountClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public synchronized String toString() {
        String ret = "Item name: " + this.itemName + " Price: " + this.price;
        return ret;
    }

    @Override
    public void buy(AccountClientInter accBuyer, String passBank) throws Rejected {
        ClientInter clientBuyer;
        try {
            // we put the client password for the bank
            accBuyer.setBankPassword(passBank);
            float balance = 0;
            clientBuyer = accBuyer.getClientRef();

            Account accountBankBuyer = null;

            Account accountBankSeller = null;
            Bank bankObj;
            try {
                bankObj = (Bank) Naming.lookup("rmi://localhost/suedenBank");
                System.out.println("Ask with log and pass: " + sellerName + "  " + refSeller.getBankPassword());
                accountBankSeller = bankObj.getAccount(sellerName, refSeller.getBankPassword());
                if (accountBankSeller == null) {
                    throw new Rejected("Rejected: wrong password for the seller");
                }
                System.out.println("Bank seller amount: " + accountBankSeller.balance());
                System.out.println("Ask with log and pass for the buyer: " + accBuyer.getClientName() + "  " + accBuyer.getBankPassword());
                accountBankBuyer = bankObj.getAccount(accBuyer.getClientName(), accBuyer.getBankPassword());
                if (accountBankBuyer == null) {
                    throw new Rejected("Rejected: wrong password for the buyer");
                }
                balance = accountBankBuyer.balance();
            } catch (NotBoundException ex) {
                Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
            } catch (MalformedURLException ex) {
                Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
            }
            List<Item> sellList = refSeller.getSellList();
            if (price > balance) {
                System.out.println("Rejected: not enought money on your account");
                throw new Rejected("Rejected: not enought money on your account");
            } else if (!sellList.contains(this)) {
                System.out.println("Item can t be sell anymore");
                throw new Rejected("Item can t be sell anymore");
            } else {
                accountBankBuyer.withdraw(price);
                accountBankSeller.deposit(price);
                System.out.println("!!!!!!!!!!!!!!!!   Size before remove: " + sellList.size());
                boolean remove = sellList.remove(this);
                boolean remove2 = sellList.remove(this);
                 
                for (int i = 0; i < sellList.size(); i++) {
                    Item item = sellList.get(i);
                    if (item.getId() == this.id) {
                        sellList.remove(i);
                    }
                }
                System.out.println("remove 1 : " + remove + " remove 2 :" + remove2);
            }
            int nbBoughtItem = accBuyer.getNbBoughtItem();
            accBuyer.setNbBoughtItem(nbBoughtItem + 1);

            int nbSoldItem = refSeller.getNbSoldItem();
            refSeller.setNbSoldItem(nbSoldItem + 1);

            System.out.println("!!!!!!!!!! Size after remove: " + sellList.size());

            ClientInter clientSeller = refSeller.getClientRef();
            if (clientSeller != null) {//si le vendeur est tjrs connecté
                CallBackThread c4 = new CallBackThread(clientSeller, "Your item: " + this.itemName + " was sold at: " + this.price + " kr.");
                Thread t4 = new Thread(c4);
                t4.start();
            }
            System.out.println("Before querie");
            try {
                sqlStatement.executeUpdate("DELETE FROM item WHERE id='" + id + "'");
                sqlStatement.executeUpdate("DELETE FROM wish WHERE idItem='" + id + "'");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            System.out.println("After query");
            if (clientBuyer != null) {
                System.out.println("In the condition");
                CallBackThread c3 = new CallBackThread(clientBuyer, "You bought the item: " + itemName + " for a price of: " + this.price + " kr.");
                Thread t3 = new Thread(c3);
                t3.start();
            }
            System.out.println("After callback");
        } catch (bankrmi.Rejected ex) {
            Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
        } catch (RemoteException ex) {
            Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void addWish(AccountClientInter accWisher, int maxPrice) throws Rejected {
        Wish wish;
        try {
            wish = new Wish((ItemInter) this, maxPrice, accWisher);
            this.wishList.add(wish);
            String strSeller = "You placed a wish on: " + this.itemName + " price: " + maxPrice + " Kr, owner: " + sellerName;
            String strWisher = "You have a wish on: " + this.itemName + " at a price of: " + maxPrice + " kr";
            System.out.println(strSeller);
            ClientInter clientWisher = accWisher.getClientRef();
            CallBackThread c1 = new CallBackThread(clientWisher, strSeller);
            Thread t1 = new Thread(c1);
            t1.start();

            if (refSeller != null) {
                ClientInter clientSeller = refSeller.getClientRef();
                if (clientSeller != null) {
                    System.out.println("ref sur seller non nulle");
                    CallBackThread c2 = new CallBackThread(clientSeller, strWisher);
                    Thread t2 = new Thread(c2);
                    t2.start();
                }
            }
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public synchronized void changePrice(AccountClientInter accOwner, int newPrice) throws Rejected {
        try {
            if ((accOwner.getClientName()).compareTo(sellerName) != 0) {
                throw new Rejected("Rejected: you are not the owner, you can't change the price");
            }
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
        this.price = newPrice;

        try {
            sqlStatement.executeUpdate("UPDATE item SET price='" + newPrice + "' WHERE id='" + id + "'");
        } catch (SQLException ex) {
            Logger.getLogger(AccountClient.class.getName()).log(Level.SEVERE, null, ex);
        }

        System.out.println("Price changed");
        for (Wish wish : wishList) {
            if (wish.getWishPrice() >= newPrice) {
                try {
                    AccountClientInter accClient = wish.getRefAccountWisher();
                    ClientInter client = accClient.getClientRef();
                    String strWish = "One of the price of your wished item has decreased";
                    if (client != null) {
                        CallBackThread c1 = new CallBackThread(client, strWish);
                        Thread t1 = new Thread(c1);
                        t1.start();
                    } else {
                        System.out.println("Client disconnect impossible to do the callBack one wisher");
                    }
                } catch (RemoteException ex) {
                    ex.printStackTrace();
                }
            }
        }
        /*
        try {
        //refSeller.getClientRef().callBackGotWish("You changed the price of one of your item");
        } catch (RemoteException ex) {
        Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
        }
         * 
         */
    }

    @Override
    public synchronized void deleteItem(AccountClientInter accOwner) throws Rejected {
        try {
            if ((accOwner.getClientName()).compareTo(sellerName) != 0) {
                throw new Rejected("Rejected: you are not the owner, you can't change the price");
            }
            if (refSeller != null) {
                List<Item> listSell = refSeller.getSellList();
                if (!listSell.remove(this)) {
                    throw new Rejected("Rejected: fail to remove item");
                }
            }
            try {
                sqlStatement.executeUpdate("DELETE FROM item WHERE id='" + id + "'");
            } catch (SQLException ex) {
                Logger.getLogger(AccountClient.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                sqlStatement.executeUpdate("DELETE FROM wish WHERE idItem='" + id + "'");
            } catch (SQLException ex) {
                Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
            }

        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * complete the list of the wisher from the information in the bdd
     */
    public synchronized void completeWishList() {
        ResultSet result;
        try {
            Market market = null;
            try {
                market = this.refSeller.getMarket();
            } catch (RemoteException ex) {
                Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
            }
            result = sqlStatement.executeQuery("SELECT * FROM wish WHERE idItem='" + this.id + "'");
            while (result.next()) {
                boolean present = false;
                for (Wish wish : wishList) {
                    ItemInter itemTemp = wish.getItem();
                    AccountClientInter accountTemp = wish.getRefAccountWisher();
                    try {
                        if ((itemTemp.getId() == result.getInt("idItem"))
                                && ((accountTemp.getClientName()).equals(result.getString("wisherName")))) {
                            present = true;
                        }
                    } catch (RemoteException ex) {
                        Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                if (!present) {
                    try {
                        AccountClientInter accWisher = market.getAccount(result.getString("wisherName"));
                        Wish addWish = new Wish(this, result.getInt("wishPrice"), accWisher);
                        this.wishList.add(addWish);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (Rejected ex) {
                        Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(Item.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
